package io.netty.myExample.duyutian.reactor模型.单线程;


import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.util.Iterator;
import java.util.Set;

/**
 * @author duyutian
 * @version 1.0
 * @date 2020/6/8 14:09
 */
class Reactor implements Runnable {
    final Selector selector;
    final ServerSocketChannel serverSocket;

    /**
     * nio无非就是定义两个东西；1、selector 多路复用器 2、channel  3、 key
     * selector 监听所有的channel 并且可以返回所有感兴趣的事件
     * channel 可以完成读写数据
     * key 监听感兴趣的事件  可以绑定附件(处理器)         接收器->处理器
     *
     * @param port
     * @throws IOException
     */
    Reactor(int port) throws IOException { //Reactor初始化
        selector = Selector.open();
        serverSocket = ServerSocketChannel.open();
        serverSocket.socket().bind(new InetSocketAddress(port));
        //非阻塞
        serverSocket.configureBlocking(false);

        //分步处理,第一步,接收accept事件
        SelectionKey sk =
                serverSocket.register(selector, SelectionKey.OP_ACCEPT);
        //attach callback object, Acceptor

        sk.attach(new Acceptor());
    }

    @Override
    public void run() {
        try {
            /**
             * 单线程的弊端在此
             * 如果分发出去的一个时间没有得到handle处理
             * 则所有就绪的事件不能处理
             */
            while (!Thread.interrupted()) {
                //这里是返回已经就绪的io的数据
                //这里会被阻塞
                System.out.println("执行");
                selector.select();
                Set selected = selector.selectedKeys();
                Iterator it = selected.iterator();
                while (it.hasNext()) {
                    //Reactor负责dispatch收到的事件
                    dispatch((SelectionKey) (it.next()));
                }
                selected.clear();
            }
        } catch (IOException ex) { /* ... */ }
    }


    void dispatch(SelectionKey k) {
        Runnable r = (Runnable) (k.attachment());
        //调用之前注册的callback对象
        if (r != null) {
            /**
             * 第一次接受accept 的时候会走 下面的Acceptor的类(通过Acceptor确定绑定的handle)
             * 在handle中替换掉了key中的attachment，为handle本身。
             */
            r.run();
        }
    }

    /**
     * 负责绑定handle
     */
    class Acceptor implements Runnable {
        @Override
        public void run() {
            try {
                SocketChannel channel = serverSocket.accept();
                if (channel != null) {
                    new Handler(selector, channel);
                }
            } catch (IOException ex) { /* ... */ }
        }
    }

    public static void main(String[] args) throws IOException {
        Reactor reactor = new Reactor(808);
        reactor.run();
    }
}
